package cn.stylefeng.guns.modular.gridsystem.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.stylefeng.guns.core.exception.ServiceException;
import cn.stylefeng.guns.core.factory.PageFactory;
import cn.stylefeng.guns.core.pojo.page.PageResult;
import cn.stylefeng.guns.modular.gridsystem.constants.ConfigSceneConstant;
import cn.stylefeng.guns.modular.gridsystem.constants.GatewayTaskTypeConstant;
import cn.stylefeng.guns.modular.gridsystem.entity.*;
import cn.stylefeng.guns.modular.gridsystem.enums.CollectionFaultEnum;
import cn.stylefeng.guns.modular.gridsystem.enums.GatewayExceptionEnum;
import cn.stylefeng.guns.modular.gridsystem.mapper.*;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizCollectionSampleManageParam;
import cn.stylefeng.guns.modular.gridsystem.model.param.CollectionModelParam;
import cn.stylefeng.guns.modular.gridsystem.model.result.BizCollectionSampleManageResult;
import cn.stylefeng.guns.modular.gridsystem.model.result.CollectionResponseResult;
import cn.stylefeng.guns.modular.gridsystem.service.BizCollectionSampleManageService;
import cn.stylefeng.guns.modular.gridsystem.service.CollectionModelService;
import cn.stylefeng.guns.modular.gridsystem.service.GatewayTaskService;
import cn.stylefeng.guns.modular.gridsystem.utils.MyFileUtils;
import cn.stylefeng.guns.sys.modular.file.entity.SysFileInfo;
import cn.stylefeng.guns.sys.modular.file.param.SysFileInfoParam;
import cn.stylefeng.guns.sys.modular.file.service.SysFileInfoService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 采集端样本管理 服务实现类
 *
 * @author ssy
 * @date 2022/02/16 10:59
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class BizCollectionSampleManageServiceImpl extends ServiceImpl<BizCollectionSampleManageMapper, BizCollectionSampleManage> implements BizCollectionSampleManageService {

    private final GatewayTaskService taskService;

    private final BizGatewayMapper gatewayMapper;

    private final BizGatewayConfigMapper configMapper;

    private final GatewayTaskRecordMapper recordMapper;

    private final CollectionModelMapper collectionModelMapper;

    private final CollectionModelService collectionModelService;
    private final SysFileInfoService fileInfoService;

    @Override
    public PageResult<BizCollectionSampleManageResult> page(BizCollectionSampleManageParam bizCollectionSampleManageParam) {
        String[] list = new String[1];
        String gatewayIds = bizCollectionSampleManageParam.getGatewayIds();
        if (StringUtils.isNotBlank(gatewayIds)) {
            list = gatewayIds.split(",");
        } else {
            list[0] = "";
        }
        // 查询分页结果
        return new PageResult<>(this.baseMapper.page(PageFactory.defaultPage(), bizCollectionSampleManageParam, list));
    }

    @Override
    public PageResult<BizCollectionSampleManageResult> pageList(BizCollectionSampleManageParam param) {
        return new PageResult<>(this.baseMapper.pageList(PageFactory.defaultPage(), param));
    }

    @Override
    public List<BizCollectionSampleManage> list(BizCollectionSampleManageParam bizCollectionSampleManageParam) {

        // 构造条件
        LambdaQueryWrapper<BizCollectionSampleManage> queryWrapper = new LambdaQueryWrapper<>();

        return this.list(queryWrapper);
    }

    @Override
    public void add(BizCollectionSampleManageParam bizCollectionSampleManageParam) {
        // 将dto转为实体
        BizCollectionSampleManage bizCollectionSampleManage = new BizCollectionSampleManage();
        BeanUtil.copyProperties(bizCollectionSampleManageParam, bizCollectionSampleManage);

        this.save(bizCollectionSampleManage);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(BizCollectionSampleManageParam param) {

        BizCollectionSampleManage sampleManage = this.getById(param.getId());

        Map<String, Object> map = new HashMap<>();
        map.put("gatewayCode", sampleManage.getGatewayCode());
        map.put("gatewayChannel", sampleManage.getGatewayChannel());
        map.put("expectAccessToken", sampleManage.getExpectAccessToken());
        map.put("expectGroupId", sampleManage.getExpectGroupId());

        List<Integer> gatewayIds = new ArrayList<>();
        gatewayIds.add(sampleManage.getGatewayId());
        // 下发删除模型任务
        taskService.add(GatewayTaskTypeConstant.DELETE_MODEL, gatewayIds, JSONUtil.toJsonStr(map));

        this.removeById(param.getId());

    }

    @Override
    public void edit(BizCollectionSampleManageParam bizCollectionSampleManageParam) {

        // 根据id查询实体
        BizCollectionSampleManage bizCollectionSampleManage = this.queryBizCollectionSampleManage(bizCollectionSampleManageParam);

        // 请求参数转化为实体
        BeanUtil.copyProperties(bizCollectionSampleManageParam, bizCollectionSampleManage);

        this.updateById(bizCollectionSampleManage);
    }

    @Override
    public BizCollectionSampleManage detail(BizCollectionSampleManageParam bizCollectionSampleManageParam) {
        return this.queryBizCollectionSampleManage(bizCollectionSampleManageParam);
    }

    /**
     * 获取通道类型
     *
     * @author ssy
     * @since 2022/02/16 10:59
     */
    private BizCollectionSampleManage queryBizCollectionSampleManage(BizCollectionSampleManageParam bizCollectionSampleManageParam) {
        BizCollectionSampleManage bizCollectionSampleManage = this.getById(bizCollectionSampleManageParam.getId());
        return bizCollectionSampleManage;
    }

    /**
     * 注册模型
     *
     * @param param
     */
    @Override
    @Transactional
    public Long registerModel(BizCollectionSampleManageParam param) {

        BizGateway gateway = gatewayMapper.selectById(param.getGatewayId());
        if (ObjectUtil.isEmpty(gateway)) {
            log.warn("网关不存在，网关主键为:{}", param.getGatewayId());
            throw new ServiceException(GatewayExceptionEnum.NOT_EXIST);
        }

        BizGatewayConfig groupIdCfg = configMapper.selectOne(new LambdaQueryWrapper<BizGatewayConfig>()
                .eq(BizGatewayConfig::getGatewayId, gateway.getId())
                .eq(BizGatewayConfig::getGatewayConfigCode, ConfigSceneConstant.MIC_GROUP_ID).last("limit 1"));
        if (ObjectUtil.isEmpty(groupIdCfg)) {
            log.warn("网关没有配置算法分组号，网关主键为：{}", param.getGatewayId());
            throw new ServiceException(GatewayExceptionEnum.NOT_CONFIG_GROUP_ID);
        }

        BizGatewayConfig accessTokenCfg = configMapper.selectOne(new LambdaQueryWrapper<BizGatewayConfig>()
                .eq(BizGatewayConfig::getGatewayId, gateway.getId())
                .eq(BizGatewayConfig::getGatewayConfigCode, ConfigSceneConstant.MIC_ACCESS_TOKEN).last("limit 1"));
        if (ObjectUtil.isEmpty(accessTokenCfg)) {
            log.warn("网关没有配置算法ID，网关主键为：{}", param.getGatewayId());
            throw new ServiceException(GatewayExceptionEnum.NOT_CONFIG_ACCESS_TOKEN);
        }

        CollectionModel collectionModel = collectionModelMapper.selectOne(new LambdaQueryWrapper<CollectionModel>()
                .eq(CollectionModel::getGatewayId, gateway.getId())
                .orderByDesc(CollectionModel::getExpectAccessToken).last("limit 1"));
        Long expectAccessToken = Long.parseLong(groupIdCfg.getConfigValue() + param.getChannel() + "001");
        if(ObjectUtil.isNotNull(collectionModel)){
            expectAccessToken = Long.parseLong(collectionModel.getExpectAccessToken()) + 1;
            log.info("groupId中存在故障模型，期望accessToken为：{}",expectAccessToken);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("faultName", param.getFaultName());
        map.put("expectGroupId", groupIdCfg.getConfigValue() + param.getChannel());
        map.put("expectAccessToken", String.valueOf(expectAccessToken));
        map.put("fileIds", param.getFileIds());

        log.info("注册网关故障模型：groupId : {},accessToken : {}",groupIdCfg.getConfigValue() + param.getChannel(),expectAccessToken);

        // 处理故障等级字典和采集端不同的问题
        switch (param.getFailureLevel()) {
            case "low":
                map.put("failureLevel", "0");
                break;
            case "middle":
                map.put("failureLevel", "1");
                break;
            case "height":
                map.put("failureLevel", "2");
                break;
        }

        List<Integer> gatewayIds = new ArrayList<>();
        gatewayIds.add(param.getGatewayId());

        CollectionModelParam collectionModelParam = new CollectionModelParam();
        collectionModelParam.setFaultName(param.getFaultName());
        collectionModelParam.setFailureLevel(param.getFailureLevel());
        collectionModelParam.setExpectAccessToken(String.valueOf(expectAccessToken));
        collectionModelParam.setExpectGroupId(groupIdCfg.getConfigValue() + param.getChannel());
        collectionModelParam.setGatewayId(gateway.getId());
        if(ObjectUtil.isNotEmpty(param.getFileIds())){
            String[] fileIds = param.getFileIds().split(",");
            collectionModelParam.setFileId(Long.parseLong(fileIds[0]));
        }
        log.info("添加网关故障模型：{}",collectionModelParam);
        collectionModelService.add(collectionModelParam);

        return taskService.add(GatewayTaskTypeConstant.REGISTER_MODEL, gatewayIds, JSONUtil.toJsonStr(map));

    }

    @Override
    public Long registerNormalModel(BizCollectionSampleManageParam param) {

        BizGateway gateway = gatewayMapper.selectById(param.getGatewayId());
        if (ObjectUtil.isEmpty(gateway)) {
            log.warn("网关不存在，网关主键为:{}", param.getGatewayId());
            throw new ServiceException(GatewayExceptionEnum.NOT_EXIST);
        }

        BizGatewayConfig groupIdCfg = configMapper.selectOne(new LambdaQueryWrapper<BizGatewayConfig>()
                .eq(BizGatewayConfig::getGatewayId, gateway.getId())
                .eq(BizGatewayConfig::getGatewayConfigCode, ConfigSceneConstant.MIC_GROUP_ID).last("limit 1"));
        if (ObjectUtil.isEmpty(groupIdCfg)) {
            log.warn("网关没有配置算法分组号，网关主键为：{}", param.getGatewayId());
            throw new ServiceException(GatewayExceptionEnum.NOT_CONFIG_GROUP_ID);
        }

        BizGatewayConfig accessTokenCfg = configMapper.selectOne(new LambdaQueryWrapper<BizGatewayConfig>()
                .eq(BizGatewayConfig::getGatewayId, gateway.getId())
                .eq(BizGatewayConfig::getGatewayConfigCode, ConfigSceneConstant.MIC_ACCESS_TOKEN).last("limit 1"));
        if (ObjectUtil.isEmpty(accessTokenCfg)) {
            log.warn("网关没有配置算法ID，网关主键为：{}", param.getGatewayId());
            throw new ServiceException(GatewayExceptionEnum.NOT_CONFIG_ACCESS_TOKEN);
        }

        Map<String, Object> map = new HashMap<>();
        map.put("expectGroupId", groupIdCfg.getConfigValue() + param.getChannel());
        map.put("expectAccessToken", accessTokenCfg.getConfigValue() + param.getChannel());
        map.put("fileIds", param.getFileIds());
        map.put("failureLevel", "0");
        map.put("faultName", "正常");

        List<Integer> gatewayIds = new ArrayList<>();
        gatewayIds.add(param.getGatewayId());

        return taskService.add(GatewayTaskTypeConstant.REGISTER_MODEL, gatewayIds, JSONUtil.toJsonStr(map));

    }

    @Override
    public CollectionResponseResult queryTask(BizCollectionSampleManageParam param) {

        CollectionResponseResult res = null;

        GatewayTaskRecord record = recordMapper.selectOne(new LambdaUpdateWrapper<GatewayTaskRecord>()
                .eq(GatewayTaskRecord::getGatewayId, param.getGatewayId())
                .eq(GatewayTaskRecord::getTaskId, param.getTaskId())
                .last("limit 1"));

        if (ObjectUtil.isEmpty(record)) {
            log.warn("远程任务不存在，远程任务主键：{}", param.getTaskId());
            throw new ServiceException(GatewayExceptionEnum.REMOTE_GATEWAY_TASK_NOT_EXIST);
        }

        if (ObjectUtil.isNotEmpty(record.getResponseResult())) {

            res = JSON.parseObject(record.getResponseResult(), CollectionResponseResult.class);

            if (res.getCode().equals(CollectionFaultEnum.GROUP_ID_OR_ACCESS_TOKEN_ERROR.getCode())) {
                res.setMsg(CollectionFaultEnum.GROUP_ID_OR_ACCESS_TOKEN_ERROR.getMessage());
            }

            if (res.getCode().equals(CollectionFaultEnum.COLLECTION_CAN_NOT_GET_FILE.getCode())) {
                res.setMsg(CollectionFaultEnum.COLLECTION_CAN_NOT_GET_FILE.getMessage());
            }

            if (res.getCode().equals(CollectionFaultEnum.COLLECTION_NO_RESPONSE.getCode())) {
                res.setMsg(CollectionFaultEnum.COLLECTION_NO_RESPONSE.getMessage());
            }

            if (res.getCode().equals(CollectionFaultEnum.COLLECTION_SERVER_ERROR.getCode())) {
                res.setMsg(CollectionFaultEnum.COLLECTION_SERVER_ERROR.getMessage());
            }

        }

        return res;

    }

    @Override
    @Transactional
    public void deleteByGatewayAndChannel(BizCollectionSampleManageParam param) {
        String channel = param.getGatewayChannel();
        Integer gatewayId = param.getGatewayId();
        LambdaQueryWrapper<BizCollectionSampleManage> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BizCollectionSampleManage::getGatewayId,gatewayId);
        queryWrapper.eq(BizCollectionSampleManage::getGatewayChannel,channel);
        List<BizCollectionSampleManage> manageList = this.baseMapper.selectList(queryWrapper);
        for (BizCollectionSampleManage sampleManage : manageList) {
            Long fileId = sampleManage.getFileId();
            SysFileInfo sysFileInfo = fileInfoService.getById(fileId);
            if(ObjectUtil.isNull(sysFileInfo)){
                //获取音频文件
                String path = MyFileUtils.getUploadPath() + "/" + sysFileInfo.getFileBucket() + "/" + sysFileInfo.getFileObjectName();
                //删除文件
                boolean isDelete = FileUtil.del(path);
                log.info("删除文件结果：{},文件路径：{}",isDelete?"成功":"失败",path);
            }
        }
        this.baseMapper.delete(queryWrapper);
    }

}
